package com.chilly.other.thread;

/**
 * 多线程并发：生产者-消费者
 * 生产者指的是负责生产数据的模块(这里模块可能是：方法、对象、线程、进程)。
 * 消费者指的是负责处理数据的模块(这里模块可能是：方法、对象、线程、进程)。
 * 消费者不能直接使用生产者的数据，它们之间有个“缓冲区”。
 * 生产者将生产好的数据放入“缓冲区”，消费者从“缓冲区”拿要处理的数据。
 * <p>
 * Created by Chilly Cui on 2020/12/8.
 */
public class ProviderConsumerDemo {

    public static void main(String[] args) {
        //定义被操作的数据对象
        //定义缓冲区
        //定义生产者
        //定义消费者

        SyncStack sStack = new SyncStack();// 定义缓冲区对象；
        Shengchan sc = new Shengchan(sStack);// 定义生产线程；
        Xiaofei xf = new Xiaofei(sStack);// 定义消费线程；
        sc.start();
        xf.start();
    }

}

class Mantou {
    int id;

    public Mantou(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

class SyncStack {//缓冲区，相当于馒头篮
    Mantou[] ms = new Mantou[10];
    int index = 0;

    //放入馒头
    public synchronized void push(Mantou m) {
        while (index == ms.length) {
            try {
                //wait后，线程会将持有的锁释放，进入阻塞状态；
                //这样其它需要锁的线程就可以获得锁；
                this.wait();
                System.out.println(this);
                //这里的含义是执行此方法的线程暂停，进入阻塞状态，
                //等消费者消费了馒头后再生产。
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 唤醒在当前对象等待池中等待的第一个线程。
        //notifyAll叫醒所有在当前对象等待池中等待的所有线程。
        this.notify();
        // 如果不唤醒的话。以后这两个线程都会进入等待线程，没有人唤醒。
        ms[index] = m;
        index++;
    }

    //拿出馒头
    public synchronized Mantou pop() {
        while (index == 0) {
            try {
                this.wait();
                System.out.println(this);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.notify();
//        System.out.println("index1=" + index);
        index--;
//        System.out.println("index2=" + index);
        return ms[index];
    }
}

class Shengchan extends Thread {// 生产者线程
    SyncStack ss = null;

    public Shengchan(SyncStack ss) {
        this.ss = ss;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("生产馒头：" + i);
            Mantou m = new Mantou(i);
            ss.push(m);
        }
    }
}

class Xiaofei extends Thread {// 消费者线程；
    SyncStack ss = null;

    public Xiaofei(SyncStack ss) {
        this.ss = ss;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            Mantou m = ss.pop();
            System.out.println("消费馒头：" + m.getId());

        }
    }
}

